/*
 * @Author: Troubadour 2276791354@qq.com
 * @Date: 2024-01-11 22:00:08
 * @LastEditors: Troubadour 2276791354@qq.com
 * @LastEditTime: 2024-01-14 20:56:18
 * @FilePath: \MDK-ARMf:\Study\STM32_Project\STM32F4_Project\OLED_Display\HARDWARE\SoftAnalogIIC\SoftAnalogIIC.c
 * @Description:
 */

#include "SoftAnalogIIC.h"

/* 1. Configures delay function. */
extern void timer_delay_us(uint16_t us);
#define SOFT_ANALOG_IIC_DELAY_US(us)        timer_delay_us(us)

/* IIC Pin state */
#define IIC_SCL_OUT_HIGH()      Set_GPIOPin_State(pIIC_Struct->SCL_GPIOx, pIIC_Struct->SCL_GPIO_Pin, GPIO_PIN_SET)
#define IIC_SCL_OUT_LOW()       Set_GPIOPin_State(pIIC_Struct->SCL_GPIOx, pIIC_Struct->SCL_GPIO_Pin, GPIO_PIN_RESET)
#define IIC_SDA_OUT_HIGH()      Set_GPIOPin_State(pIIC_Struct->SDA_GPIOx, pIIC_Struct->SDA_GPIO_Pin, GPIO_PIN_SET)
#define IIC_SDA_OUT_LOW()       Set_GPIOPin_State(pIIC_Struct->SDA_GPIOx, pIIC_Struct->SDA_GPIO_Pin, GPIO_PIN_RESET)
#define IIC_Write_Bit(bit)      Set_GPIOPin_State(pIIC_Struct->SDA_GPIOx, pIIC_Struct->SDA_GPIO_Pin, (bit) ? (GPIO_PIN_SET) : (GPIO_PIN_RESET))
#define IIC_SDA_ReadPin()       Read_Sda_State(pIIC_Struct->SDA_GPIOx, pIIC_Struct->SDA_GPIO_Pin)
/* IIC Pin Mode */
#define IIC_SCL_OUT_MODE()      Set_GPIOPin_Mode(pIIC_Struct->SCL_GPIOx, pIIC_Struct->SCL_GPIO_Pin, IIC_OUTPUT_MODE)
#define IIC_SDA_OUT_MODE()      Set_GPIOPin_Mode(pIIC_Struct->SDA_GPIOx, pIIC_Struct->SDA_GPIO_Pin, IIC_OUTPUT_MODE)
#define IIC_SDA_INT_MODE()      Set_GPIOPin_Mode(pIIC_Struct->SDA_GPIOx, pIIC_Struct->SDA_GPIO_Pin, IIC_INPUT_MODE)

/**
 * @function: Set_GPIOPin_Mode
 * @brief 设置Gpio模式
 * @param {*}
 * @return {*}
 */
static void Set_GPIOPin_Mode(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, SoftAnalogIIC_PinState mode)
{
    /* 2. Configures GPIO init. */
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = GPIO_Pin;
    if (mode == IIC_OUTPUT_MODE)
    {
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    }
    else
    {
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    }

    HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}

/**
 * @function: Set_GPIOPin_State
 * @brief 设置Gpio 引脚状态
 * @param {*}
 * @return {*}
 */
static void Set_GPIOPin_State(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
{
    /* 3. Configures GPIO mode. */
    HAL_GPIO_WritePin(GPIOx, GPIO_Pin, PinState);
}

/**
 * @function: Read_Sda_State
 * @brief 读取Gpio 引脚状态
 * @param {*}
 * @return {*}
 */
/**
 * @description: Read_Sda_State
 * @brief 读取Gpio 引脚状态
 * @param {*}
 * @return {*}
 */
static uint8_t Read_Sda_State(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
    /* 4. Configures GPIO state. */
    return HAL_GPIO_ReadPin(GPIOx, GPIO_Pin);
}

/**
 * @function: SoftAnalogIIC_Init
 * @brief IIC初始化
 * @param {SoftAnalogIIC_Typedef} pIIC_Struct：IIC结构体
 * @return {*}
 */
void SoftAnalogIIC_Init(SoftAnalogIIC_Typedef *pIIC_Struct)
{
    IIC_SCL_OUT_MODE();
    IIC_SDA_OUT_MODE();
    IIC_SCL_OUT_HIGH();
    IIC_SDA_OUT_HIGH();
}

/**
 * @function: IIC_Start
 * @brief 产生IIC启动信号
 * @param {SoftAnalogIIC_Typedef} pIIC_Struct：IIC结构体
 * @return {*}
 */
void SoftAnalogIIC_Start(SoftAnalogIIC_Typedef *pIIC_Struct)
{
    IIC_SDA_OUT_MODE();
    IIC_SDA_OUT_HIGH();
    IIC_SCL_OUT_HIGH();
    SOFT_ANALOG_IIC_DELAY_US(4);
    IIC_SDA_OUT_LOW();
    SOFT_ANALOG_IIC_DELAY_US(4);
    IIC_SCL_OUT_LOW();
}

/**
 * @function: SoftAnalogIIC_Stop
 * @brief 产生IIC停止信号
 * @param {SoftAnalogIIC_Typedef} pIIC_Struct：IIC结构体
 * @return {*}
 */
void SoftAnalogIIC_Stop(SoftAnalogIIC_Typedef *pIIC_Struct)
{
    IIC_SDA_OUT_MODE();
    IIC_SCL_OUT_LOW();
    IIC_SDA_OUT_LOW();
    SOFT_ANALOG_IIC_DELAY_US(4);
    IIC_SCL_OUT_HIGH();
    IIC_SDA_OUT_HIGH();
    SOFT_ANALOG_IIC_DELAY_US(4);
}

/**
 * @function: IIC_Wait_Ack
 * @brief 等待ACK应答
 * @param {SoftAnalogIIC_Typedef} pIIC_Struct：IIC结构体
 * @return {SoftAnalogIIC_State} IIC_OK：有应答；IIC_ERROR：超时，无应答
 */
SoftAnalogIIC_State SoftAnalogIIC_Wait_Ack(SoftAnalogIIC_Typedef *pIIC_Struct)
{
    uint8_t ucErrTime = 0;

    IIC_SDA_INT_MODE();
    SOFT_ANALOG_IIC_DELAY_US(1);
    IIC_SCL_OUT_HIGH();
    SOFT_ANALOG_IIC_DELAY_US(1);

    while (IIC_SDA_ReadPin())
    {
        ucErrTime++;
        if (ucErrTime > 250)
        {
            SoftAnalogIIC_Stop(pIIC_Struct);
            return IIC_ERROR;
        }
    }
    IIC_SCL_OUT_LOW();
    return IIC_OK;
}

/**
 * @function: SoftAnalogIIC__Ack
 * @brief 产生ACK应答
 * @param {SoftAnalogIIC_Typedef} pIIC_Struct：IIC结构体
 * @return {*}
 */
void SoftAnalogIIC_Ack(SoftAnalogIIC_Typedef *pIIC_Struct)
{
    IIC_SCL_OUT_LOW();
    IIC_SDA_OUT_MODE();
    IIC_SDA_OUT_LOW();
    SOFT_ANALOG_IIC_DELAY_US(2);
    IIC_SCL_OUT_HIGH();
    SOFT_ANALOG_IIC_DELAY_US(2);
    IIC_SCL_OUT_LOW();
}

/**
 * @function: SoftAnalogIIC_NAck
 * @brief 不产生ACK应答
 * @param {SoftAnalogIIC_Typedef} pIIC_Struct：IIC结构体
 * @return {*}
 */
void SoftAnalogIIC_NAck(SoftAnalogIIC_Typedef *pIIC_Struct)
{
    IIC_SCL_OUT_LOW();
    IIC_SDA_OUT_MODE();
    IIC_SDA_OUT_HIGH();
    SOFT_ANALOG_IIC_DELAY_US(2);
    IIC_SCL_OUT_HIGH();
    SOFT_ANALOG_IIC_DELAY_US(2);
    IIC_SCL_OUT_LOW();
}

/**
 * @function:SoftAnalogIIC_Send_Byte
 * @brief IIC发送一个字节
 * @param {SoftAnalogIIC_Typedef} pIIC_Struct：IIC结构体
 * @param {uint8_t} txd：要发送的数据
 * @return {*}
 */
void SoftAnalogIIC_Send_Byte(SoftAnalogIIC_Typedef *pIIC_Struct, uint8_t dataByte)
{
    uint8_t i = 0;

    IIC_SDA_OUT_MODE();
    IIC_SCL_OUT_LOW();

    for (i = 0; i < 8; i++)
    {
        IIC_Write_Bit((dataByte & 0x80) >> 7);
        dataByte <<= 1;
        SOFT_ANALOG_IIC_DELAY_US(2);
        IIC_SCL_OUT_HIGH();
        SOFT_ANALOG_IIC_DELAY_US(2);
        IIC_SCL_OUT_LOW();
    }
}

/**
 * @function: SoftAnalogIIC_Read_Byte
 * @brief 读1个字节
 * @param {SoftAnalogIIC_Typedef} pIIC_Struct：IIC结构体
 * @param {uint8_t} ack：ack=1时，发送ACK；ack=0，发送No ACK
 * @return {uint8_t} receive：返回读到的1个字节
 */
uint8_t SoftAnalogIIC_Read_Byte(SoftAnalogIIC_Typedef *pIIC_Struct, uint8_t ack)
{
    uint8_t i = 0, receive = 0;

    IIC_SDA_INT_MODE();
    for (i = 0; i < 8; i++)
    {
        IIC_SCL_OUT_LOW();
        SOFT_ANALOG_IIC_DELAY_US(2);
        IIC_SCL_OUT_HIGH();
        receive <<= 1;
        if (IIC_SDA_ReadPin())
        {
            receive++;
        }
        if (ack)
        {
            SoftAnalogIIC_Ack(pIIC_Struct);
        }
        else
        {
            SoftAnalogIIC_NAck(pIIC_Struct);
        }
        SOFT_ANALOG_IIC_DELAY_US(2);
    }

    return receive;
}
